#include "pch.h"
#include "analysis.h"

void analysis::analy_object()
{
	object_info o_info;
	o_info.name = get_word(RTYPE_TOKEN);
	Token t = ts.get_token();
	if (t.type != SYMBAL_TOKEN)
	{
		ts.putback(t);
		while (true)
		{
			argument arg = get_argument();
			o_info.properties.push_back(arg);
			t = ts.get_token();
			if (t.wchar == END_TOKEN)
			{
				types.push_back(o_info);
				break;
			}
			else if (t.wchar != NEXT_TOKEN)
			{
				throw Error("Bad Expression", __FILE__, __LINE__);
			}
		}
	}
	else
		throw Error("Bad Expression", __FILE__, __LINE__);
	types.push_back(o_info);
}

void analysis::analy_method()
{
	method_info m_info;
	m_info.name = get_word(RMETHOD_TOKEN);
	Token t = ts.get_token();
	if (t.type != SYMBAL_TOKEN || t.wchar != LAREA_TOKEN)
		throw Error("Bad Expression",
			__FILE__, __LINE__);
	while (true)
	{
		code c = get_method_code();
		m_info.body.push_back(c);
		t = ts.get_token();
		if (t.type != SYMBAL_TOKEN)
			throw Error("Bad Expression", __FILE__, __LINE__);
		if (t.wchar == RAREA_TOKEN)break;
	}
	methods.push_back(m_info);
}

void analysis::analy_describe()
{
	describe_info d_info;
	d_info.name = get_word(TAG_TOKEN);
	std::wstring tag_name = get_word(DEFINE_TOKEN);
	d_info.target = get_object_info(tag_name);
	Token t = ts.get_token();
	if(t.type != SYMBAL_TOKEN || t.wchar != LAREA_TOKEN)
		throw Error("Bad Expression",
			__FILE__, __LINE__);
	while (true)
	{
		code c = get_method_code();
		d_info.body.push_back(c);
		t = ts.get_token();
		/*if (t.type != SYMBAL_TOKEN)
			throw Error("Bad Expression", __FILE__, __LINE__);*/
		if (t.wchar == RAREA_TOKEN)break;
		else
			ts.putback(t);
	}
	describes.push_back(d_info);
}

void analysis::analy_code()
{
	if (ts.eof()) return;
	code c;
	Token t = ts.get_token();
	while (true)
	{
		switch (t.type)
		{
		case SYMBAL_TOKEN:
			if (t.wchar == END_TOKEN)
			{
				c.tokens.push_back(t);
				codes.push_back(c);
				return;
			}
			c.tokens.push_back(t);
			break;
		case MARK_TOKEN:
			ts.putback(t);
			t = find_word();
			if (t.type == NONE_TOKEN)
				throw Error("Name Not Define", __FILE__, __LINE__);
			c.tokens.push_back(t);
			break;
		default:
			c.tokens.push_back(t);
			break;
		}
		if (ts.eof())
			throw Error("Bad Ending", __FILE__, __LINE__);
		t = ts.get_token();
	}
}

void analysis::analy()
{
	while (true)
	{
		Token t = ts.get_token();
		switch (t.type)
		{
		case MARK_TOKEN:
			ts.putback(t);
			analy_code();
			break;
		case SYMBAL_TOKEN:
		{
			switch (t.wchar)
			{
			case LTYPE_TOKEN:
				analy_object();
				break;
			case LMETHOD_TOKEN:
				analy_method();
				break;
			case DESCRIBE_TOKEN:
				analy_describe();
				break;
			}
			break;
		}
		case KEYWORD_TOKEN:
		{
			if (t.wchar == TALK_TOKEN)
			{
				ts.putback(t);
				analy_code();
			}
			break;
		}
		case NONE_TOKEN:
			return;
		default:
			throw Error("error", __FILE__, __LINE__);
			break;
		}
	}
}

std::wstring analysis::get_word(wchar_t w)
{
	std::wstring word = L"";
	while (true)
	{
		Token t = ts.get_token();
		if (t.type == SYMBAL_TOKEN && t.wchar == w)
			return word;
		if (t.type != MARK_TOKEN)
			throw Error("Bad Token", __FILE__, __LINE__);
		word += t.wchar;
	}
	throw Error("Bad Token", __FILE__, __LINE__);
	return L"";
}

Token analysis::find_word()
{
	std::wstring word;
	Token t;
	Token ret(WORD_TOKEN);
	while (true)
	{
		if (ts.eof())
			throw Error("Bad Ending", __FILE__, __LINE__);
		t = ts.get_token();
		switch (t.type)
		{
		case MARK_TOKEN:
			word += t.wchar;
			for (method_info m : methods) 
			{
				if (m.name == word)
				{
					ret.word = word;
					ret.second_type = METHOD_WORD_TOKEN;
					return ret;
				}
			}
			for (object_info o : types)
			{
				if (o.name == word)
				{
					ret.word = word;
					ret.second_type = OBJECT_WORD_TOKEN;
					return ret;
				}
			}
			for (describe_info d : describes)
			{
				if (d.name == word)
				{
					ret.word = word;
					ret.second_type = DESCRIBE_WORD_TOKEN;
					return ret;
				}
			}
			for (std::wstring s : vars)
			{
				if (s == word)
				{
					ret.word = word;
					ret.second_type = VAR_WORD_TOKEN;
					return ret;
				}
			}
			break;
		case KEYWORD_TOKEN:
			if (t.wchar == ASG_TOKEN)
			{
				ts.putback(t);
				vars.push_back(word);
				ret.word = word;
				ret.second_type = VAR_WORD_TOKEN;
				return ret;
			}
			else if (t.wchar == DOT_TOKEN)
			{
				ts.putback(t);
				vars.push_back(word);
				ret.word = word;
				ret.second_type = DESCRIBE_TOKEN;
				return ret;
			}
		case SYMBAL_TOKEN:
			switch (t.wchar)
			{
			case END_TOKEN:
				ts.putback(t);
				vars.push_back(word);
				ret.word = word;
				ret.second_type = VAR_WORD_TOKEN;
				return ret;
			}
		default:
			throw Error("Name not Define", __FILE__, __LINE__);
		}
	}
	return none_token;
}
